package middleware.llvm.value;

import middleware.llvm.BasicBlock;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 函数的IR形式
 *
 * @author 杨凯伟
 * @date 2024/10/30
 */
public class FunctionIRType extends Value {


    private final IRType retType;
    private final List<FunctionArgumentIRType> arguments = new ArrayList<>();
    private final List<BasicBlock> basicBlocks = new ArrayList<>();

    public static FunctionIRType BUILD_IN_GETINT = new FunctionIRType(IRType.getInt(), List.of());
    public static FunctionIRType BUILD_IN_GETCHAR = new FunctionIRType(IRType.getChar(), List.of());
    public static FunctionIRType BUILD_IN_PUTINT = new FunctionIRType(IRType.getVoid(), List.of(IRType.getInt()));
    public static FunctionIRType BUILD_IN_PUTCH = new FunctionIRType(IRType.getVoid(), List.of(IRType.getInt()));
    public static FunctionIRType BUILD_IN_PUTSTR = new FunctionIRType(IRType.getVoid(), List.of(IRType.getChar().ptr(1)));

    static {
        BUILD_IN_GETINT.setName("getint");
        BUILD_IN_GETCHAR.setName("getchar");
        BUILD_IN_PUTINT.setName("putint");
        BUILD_IN_PUTCH.setName("putch");
        BUILD_IN_PUTSTR.setName("putstr");
    }

    public FunctionIRType(IRType retType, List<IRType> argTypes) {
        super(retType);
        this.retType = retType;
        for (var argType : argTypes) {
            arguments.add(new FunctionArgumentIRType(argType));
        }
    }

    public BasicBlock getFirstBasicBlock() {
        if (basicBlocks.isEmpty()) {
            return null;
        } else {
            return basicBlocks.get(0);
        }
    }

    public IRType getRetType() {
        return retType;
    }

    public List<FunctionArgumentIRType> getArguments() {
        return arguments;
    }

    public List<BasicBlock> getBasicBlocks() {
        return basicBlocks;
    }

    public BasicBlock createBasicBlock() {
        var newBlock = new BasicBlock(this);
        basicBlocks.add(newBlock);
        return newBlock;
    }

    public int calcParamSpace() {
        return arguments.size() * 4;
    }

    @Override
    public String getName() {
        return "@" + super.getName();
    }

    public void dump(PrintStream out) {
        out.printf("define dso_local %s %s(", retType.toString(), getName());

//        boolean isFirst = true;
//        for (var arg : arguments) {
//            if (isFirst) {
//                isFirst = false;
//            } else {
//                out.print(", ");
//            }
//            arg.dump(out);
//        }
//
//        out.print(") {\n");
//
//        for (var block : basicBlocks) {
//            block.dump(out);
//        }
        Iterator<FunctionArgumentIRType> argIterator = arguments.iterator();
        while (argIterator.hasNext()) {
            FunctionArgumentIRType arg = argIterator.next();
            if (!argIterator.hasNext()) {
                out.print(", ");
            }
            arg.dump(out);
        }
        basicBlocks.forEach(block -> block.dump(out));
        out.print(") {\n");
        out.print("}\n");
    }
}
